package psd;
import psd.WU.*;

public class RegRecord {

	static int id_cntr = 1000;

	public boolean add_to_list;

	public String email;

	public String friends;

	private boolean friendship; // friendship dates okay

	public boolean fromEB, fromNB, fromSB, fromSE, fromPN, fromSF;

	public enum GroupStyle { ANY, ALL }
	private GroupStyle groupStyle = null; // group dating style

	public enum LookKinkHow { ONLY, EITHER, NONE, UNDEFINED }

	private boolean hasID; // has id been set?

	public String id = "N" + (id_cntr += 10 + (int)(Math.random()*100.0));

	private String oldID; // passed prev. id code

	public boolean isGroup; // is this record a group?

	private String childcareDetails;

	private boolean needChildcare = false;



	public enum LookGroupHow { ONLY, ANY, ALL, NO };

	public LookGroupHow lookGroup; // open to dating groups?

	public boolean stationary = false; // does this person not like moving about?

	Person NULL_PERSON = new Person();

	int numPeeps;

	Person[] peeps = null;

	private String pubname;

	private String referred;

	private String remarks;


	int timestamp = 0;

	private boolean coming = true;
	private String notes;

	private boolean paid;
	private boolean pending;
	

	RegRecord( boolean group ) {
		isGroup = group;
		NULL_PERSON.lookKink = LookKinkHow.UNDEFINED;
	}

	public boolean allLike( Person whop ) {
		for ( Person p : peeps() ) {
			if ( p.inactive() ) {
				continue;
			}

			if ( !p.mutual( whop ) ) {
				return false;
			}
		}
		return true;
	}

	// is everyone in this record liked by whop?
	public boolean allLikedBy( Person whop ) {
		for ( Person p : peeps() ) {
			if ( p.inactive() ) {
				continue;
			}

			if ( !p.mutual( whop ) ) {
				return false;
			}
		}
		return true;
	}

	private boolean anyGroupStyle() {
		return groupStyle.equals( GroupStyle.ANY );
	}

	// does any of our folks like all of the people in whop?
	public boolean anyLikeAll( RegRecord whop ) {
		for ( Person p : peeps() ) {
			if ( p.inactive() ) {
				continue;
			}

			if ( whop.allLikedBy( p ) ) {
				return true;
			}
		}
		return false;
	}

	public boolean anyMutualLike( Person whop ) {
		for ( Person p : peeps() ) {
			if ( p.inactive() ) {
				continue;
			}

			if ( p.mutual( whop ) ) {
				return true;
			}
		}
		return false;
	}

	public boolean bigendered() {
		return isMale() && isFemale();
	}

	public void buildID(String fileName, boolean filename_id_flag) {
		String[] fns = fileName.split( "[_\\.]");
		if ( hasID ) {
			return;
		}

		if ( filename_id_flag ) {
			id = fileName.substring(0,fileName.length()-4).replace("-",".");
		} else {
			id = initials() + fns[1].substring(0,3);
		}
	}

	private void checkPeep(int pos ) {
		if ( numPeeps == pos ) {
			addPeep( new Person() );
		}
	}


	private boolean havePeep(int pos, String where ) {

		return havePeep( pos, where, false );
	}

	private boolean havePeep(int pos, String where, boolean silent) {
		if ( numPeeps > pos ) {
			return true;
		} else {
			if ( !silent ) {
				System.out.println( id() + ":Warning: ignoring variable since no person to attach it to (" + where + ")");
			}
			return false;
		}
	}


	public void cleanUp() {

		setPubname(cleanString( pubname() ));

		isGroup = numPeeps > 1;

		if (pubname() == null ) {
			if ( isGroup ) {
				setPubname(first(0) + " & " + first(1));
			} else {
				setPubname(first());
			}
			if ( pubname() != null ) {
				setPubname(pubname().toLowerCase());
			}
		}

		if ( lookGroup == null ) {
			lookGroup = LookGroupHow.NO;
		}


		if ( groupStyle == null ) {
			groupStyle = GroupStyle.ALL;
		}
	}

	String first() {
		checkPeep(0);
		return peeps[0].first;
	}
	String first( int pos ) {
		return peeps[pos].first;
	}
	public boolean genderCross(RegRecord targ) {
		return ( isMale() && targ.isFemale() )
		|| ( isFemale() && targ.isMale() );	
	}
	public boolean genderMatch(RegRecord targ) {
		return ( isMale() && targ.isMale() )
		|| ( isFemale() && targ.isFemale() );
	}

	private boolean groupOK() {
		return lookGroup != LookGroupHow.NO;
	}

	private boolean groupOnly() {
		return lookGroup == LookGroupHow.ONLY;
	}

	public boolean hasID() {
		return hasID;
	}

	public boolean hasName() {
		if ( numPeeps == 0 ) {
			return false;
		}
		return first() != null || last() != null;
	}

	String id() {
		return id;
	}

	private Person indiv() {
		if ( numPeeps > 1 ) { 
			throw new RuntimeException( "Group being treated as individual! (" + id() + ")" );
		} else {
			return peeps[0];
		}
	}

	String initials() {
		String s = null;
		if ( isGroup ) {
			s =  "" + peeps[0].first.charAt(0) + peeps[1].first.charAt(0);

		} else {
			if ( last() != null && last().length() > 0 ) {
				s= ""+ first().charAt(0) + last().charAt(0);
			} else {
				s= ""+ first().charAt(0);
			}
		}
		return s.toUpperCase();
	}

	public boolean isBi() {
		return wantMale() && wantFemale();
	}

	boolean isFemale() {
		for ( Person p : peeps ) {
			if ( p.woman ) { 
				return true;
			}
		}
		return false;
	}

	boolean isMale() {
		for ( Person p : peeps ) {
			if ( p.man ) { 
				return true;
			}
		}
		return false;
	}


	String last( ) {
		return peeps[0].last;
	}



	String last( int pos ) {
		return peeps[pos].last;
	}

	private Person[] peeps() {
		Person[] p = new Person[ numPeeps ];
		for ( int i = 0; i < numPeeps; i++ ) {
			p[i] = peeps[i];
		}
		return p;
	}

	public void setAge(int age, int pos) {
		checkPeep(pos);
		peeps[pos].age = age;
		if ( peeps[pos].minAge == 0 ) peeps[pos].minAge = age / 2;
		if ( peeps[pos].maxAge == 0 ) peeps[pos].maxAge = (int) (age * 1.5);
	}


	public void setFirst(String fname, int pos) {
		checkPeep(pos);
		peeps[pos].first = cleanString( fname );

	}

	public void setFriendship(boolean f) {
		friendship = f;
	}

	public void setGQ(boolean b, int pos) {
		checkPeep(pos);
		peeps[pos].GQ = b;
	}

	public void setGroupStyle(String style) {
		if ( style.equals( "any" ) ) {
			groupStyle = GroupStyle.ANY;
		} else {
			groupStyle = GroupStyle.ALL;
		}
	}

	public void setGroupStyleAnyOK(boolean anyOK ) {
		if (  anyOK ) {
			groupStyle = GroupStyle.ANY;
		} else {
			groupStyle = GroupStyle.ALL;
		}
	}


	public void setID(String id) {
		hasID = true;
		this.id = id;
	}

	public void setIDCode(String code) {
		oldID = code;
	}
	public void setLast(String lname, int pos) {
		checkPeep(pos);
		peeps[pos].last = cleanString( lname );
	}
	public void setLookGQ(boolean b, int pos) {
		checkPeep(pos);
		peeps[pos].lookGQ = b;
	}

	public void setLookM(boolean b, int pos) {
		checkPeep(pos);
		peeps[pos].lookM = b;
	}
	public void setLookNone(boolean b, int pos) {
		checkPeep(pos);
		peeps[pos].lookNone = b;
	}

	public void setLookTransM(boolean b, int pos) {
		checkPeep(pos);
		peeps[pos].lookTM = b;

	}

	public void setLookTransW(boolean b, int pos) {
		checkPeep(pos);
		peeps[pos].lookTW = b;

	}

	public void setLookW(boolean b, int pos) {
		checkPeep(pos);
		peeps[pos].lookW = b;
	}

	public void setMan(boolean b, int pos) {
		checkPeep(pos);
		peeps[pos].man = b;
	}

	public void setMaxAge(int max, int pos) {
		checkPeep(pos);
		peeps[pos].maxAge = max;
	}
	public void setMinAge(int min, int pos) {
		checkPeep(pos);
		peeps[pos].minAge = min;
	}
	public void setTransM(boolean b, int pos) {
		checkPeep(pos);
		peeps[pos].transM = b;
	}
	public void setTransW(boolean b, int pos) {
		checkPeep(pos);
		peeps[pos].transW = b;
	}
	public void setWoman(boolean b, int pos) {
		checkPeep(pos);
		peeps[pos].woman = b;
	}

	public String toString() {
		String outputString = id() + "," + oldID + "," + timestamp + "," + WU.yesBlank(isGroup) + "," + groupStyle + "," + pubname() + "," + email;

		outputString += "," + lookGroup +  "," + WU.yesBlank(friendship) 
		+ "," + WU.yesBlank(stationary) 
		+ "," + WU.yesBlank(noPrimary());

		return outputString;
	}


	public String toString( boolean write_comments_flag ) {
		String outputString = id() + "," + oldID + "," + timestamp + "," + WU.yesBlank(isGroup) + "," + groupStyle + "," + pubname() + "," + email;

		if ( write_comments_flag ) {
			outputString += "," + WU.yesBlank(add_to_list);
		}
		outputString += "," + lookGroup +  "," + WU.yesBlank(friendship) 
		+ "," + WU.yesBlank(stationary) 
		+ "," + WU.yesBlank(noPrimary());
		for ( int i = 0; i < 4; i++ ) {
			if ( i < numPeeps ) {
				outputString += "," + peeps[i].toString(write_comments_flag);
			} else {
				outputString += "," + NULL_PERSON.toString(write_comments_flag);
			}
		}


		if ( write_comments_flag ) {
			outputString += "," + WU.yesBlank(fromEB) 
			+ "," + WU.yesBlank(fromSB) 
			+ "," + WU.yesBlank(fromNB) 
			+ "," + WU.yesBlank(fromSF) 
			+ "," + WU.yesBlank(fromPN) 
			+ "," + WU.yesBlank(fromSE);
		}

		if ( write_comments_flag ) {
			outputString += "," + getReferred() + "," + friends + "," + getComments();
		}

		outputString += "," + geekCode() + "," + WU.yesNo(coming) + "," + getNotes();

		outputString = outputString.replaceAll(",null,", ",," );
		outputString = outputString.replaceAll(",null,", ",," );

		return outputString;
	}


	public String getComments() {
		if ( remarks == null ) {
			return "";
		} else {
			return cleanString( remarks );
		}
	}

	public String allNames() {
		String s = "";
		for ( int i = 0; i < numPeeps; i++ ) {
			Person p = peeps[i];
			if ( i > 0 ) {
				s += ", ";
			}
			s += p.first + " " + p.last;
		}
		return s;
	}
	
	public String geekCode() {
		String s = "";
		if ( !isGroup ) {
			s = peeps[0].geekCode( true );
		} else {
			s = "a group of " + peeps[0].geekCode(false); 

			for ( int i = 1; i < numPeeps; i++ ) {
				s += " and " + peeps[i].geekCode(false);
			}

			if ( groupStyle == GroupStyle.ANY ) {
				s += " (matching one is fine)";
			} else {
				s += " (all must match)";
			}
		}

		s += ".";

		if ( lookGroup == LookGroupHow.ALL ) 
			s += "  Groups okay if all match.";
		else if ( lookGroup == LookGroupHow.ANY ) 
			s += "  Individuals in a group okay.";
		else if ( lookGroup ==  LookGroupHow.NO )
			s += "  Groups not okay.";
		else if ( lookGroup ==  LookGroupHow.ONLY ) 
			s += "  Groups only.";

		if ( friendship ) {
			s += "  Friendship dates okay.";
		} else {
			s += "  No friendship dates.";
		}

		if ( stationary ) {
			s += "  Needs to stay in same spot.";
		}

		s += "  From ";
		String ss = "";
		if ( fromEB ) ss += "the East Bay and ";
		if ( fromSB ) ss += "the South Bay and ";
		if ( fromNB ) ss += "the North Bay and ";
		if ( fromSF ) ss += "SF and ";
		if ( fromPN ) ss += "the Peninsula and ";
		if ( fromSE ) ss += "points unknown and ";
		if ( ss.equals("") ) {
			s += "  No location given.";
		} else {
			s += ss.substring(0, ss.length()-5) + ".";
		}

		return s;
	}

	public boolean ungendered() {
		return !isFemale() && !isMale();
	}

	private boolean wantFemale() {
		for ( Person p : peeps ) {
			if ( p.lookW ) { 
				return true;
			}
		}
		return false;
	}
	private boolean wantMale() {
		for ( Person p : peeps ) {
			if ( p.lookM ) { 
				return true;
			}
		}
		return false;
	}

	public int willDate( RegRecord who ) {

		//if ( GQ ) { throw new RuntimeException( "Not yet able to match GQ folks" ); }

		if ( who.isGroup && !groupOK() ) { // we are looking at a group
			return 0;
		}
		if ( !who.isGroup && groupOnly() ) { // group only, and who isn't a group!
			return 0;
		}

		int locbonus = 0;
		if ( ( fromEB && who.fromEB )
				|| ( fromNB && who.fromNB ) 
				|| ( fromSB && who.fromSB ) 
				|| ( fromSE && who.fromSE ) 
				|| ( fromSF && who.fromSF )
				|| ( fromPN && who.fromPN )) {
			locbonus = 2;
		}

		if ( isGroup ) {
			if ( who.isGroup ) { // we are group, and they are too

				if ( who.anyGroupStyle() ) {
					for ( Person whop : who.peeps() ) {
						if ( anyMutualLike( whop ) ) {
							return 1 + locbonus;
						} 
					}
					return 0;

				} else { // they want to date as a unit--so all of them must be liked by someone

					for ( Person whop : who.peeps() ) {
						if ( !whop.inactive() && !anyMutualLike( whop ) ) {
							return 0;
						}
					}
					return 1 + locbonus;
				}
			} else { // we are group looking at an individual
				Person whop = who.indiv();

				if ( anyGroupStyle() ) {
					return anyMutualLike( whop ) ? (1+locbonus) : 0;
				} else { // all must match
					return allLike( whop ) ? (2+locbonus) : 0;
				}
			}
		} else { // we are individual -- will we date who?
			Person us = indiv();
			if ( who.isGroup ) {
				if ( who.anyGroupStyle() && !(lookGroup==LookGroupHow.ALL) ) { 
					// they will loan out single members, and we are okay with that.  So...
					//--do we like one of em?
					int scB = 0;
					for ( Person p : who.peeps() ) {
						int sc = us.willDate( p );
						if ( sc > scB ) {
							scB = sc;
						}
					}
					return (scB > 0) ? scB + locbonus : 0;
				} else { // we must like all of them to want to date them.
					int scB = 0;
					for ( Person p : who.peeps() ) {
						if ( !p.inactive() ) {
							int sc = us.willDate( p );
							if ( sc == 0 ) {
								return 0;
							}
							if (scB < sc ) {
								scB = sc;
							}
						}
					}
					return scB + locbonus;
				}
			} else { // indiv-indiv dating
				int sc = us.willDate( who.indiv() );

				if ( sc > 0 ) {
					if ( noPrimary() && who.noPrimary() ) {
						sc+=2;
					}
					return sc + locbonus;
				} else {
					return 0;
				}
			}
		}
	} // end willDate (RegRecord)

	private boolean noPrimary() {
		return peeps.length == 1 && peeps[0].noPrimary;
	}

	public void setGroup(boolean b) {
		isGroup = b;

	}

	public String info() {
		return id() + ",\t" + (getReferred() != null ? getReferred() : "") + "\n" + (remarks != null ? remarks : "" ) + "\n";
	}

	public void setLookGroup(String style) {
		if ( style.equals( "yesAny" ) ) {
			lookGroup  = LookGroupHow.ANY;
		} else if ( style.equals( "no" ) ) {
			lookGroup = LookGroupHow.NO;
		} else if ( style.equals( "only" ) ) {
			lookGroup = LookGroupHow.ONLY;
		} else if ( style.equals( "yes" ) ) {
			lookGroup = LookGroupHow.ANY;
		} else {
			lookGroup = LookGroupHow.ALL;
		}
	}

	public void setLookGroup(boolean groupOK, boolean anyOK ) {
		if ( groupOK ) {
			if ( anyOK ) {
				lookGroup = LookGroupHow.ANY;
			} else {
				lookGroup = LookGroupHow.ALL;
			}
		} else {
			lookGroup = LookGroupHow.NO;
		}
	}


	public void setKinky(boolean isKinky, int pos) {
		if ( havePeep(pos, "setKinky") ) {
			peeps[pos].kinky = isKinky;
		} 
	}



	public void setLookKinky(String lookKinkS, int pos) {
		if ( havePeep(pos, "setLookKinky", lookKinkS.equals("either") ) ) {
			if ( lookKinkS.startsWith( "o" ) ) {
				peeps[pos].lookKink = LookKinkHow.ONLY;
			} else if ( lookKinkS.startsWith( "n" ) ) {
				peeps[pos].lookKink = LookKinkHow.NONE;
			} else if ( lookKinkS.startsWith("e") ) {
				peeps[pos].lookKink = LookKinkHow.EITHER;
			} else {
				throw new RuntimeException( "Kink search of '" + lookKinkS + "' is not understood." );
			}
		}
	}

	public void setTimeStamp(int i) {
		timestamp = i;
	}

	public void buildTmpID(String fileName) {
		buildID(fileName, true );
		hasID = false;
	}

	public void setComing(boolean paid) {
		this.coming = paid;
	}

	public boolean isComing() {
		return coming;
	}

	public void setNotes(String notes) {
		notes = cleanString(notes);
		if ( notes == null || notes.equals("") ) {
			return;
		}
		if ( this.notes == null ) {
			this.notes = notes;
		} else {
			this.notes += "; " + notes;
		}
	}

	private String cleanString(String s) {
		if ( s == null ) {
			return null;
		}
		s =  s.replaceAll( "[,\n\f\r]+", " ").trim();
		if ( s.equals("") ) {
			return null;
		}
		return s;
	}

	public String getNotes() {
		if ( notes == null ) {
			return "";
		}
		return notes;

	}
	
	boolean singleStraightMan() {
		return ( numPeeps == 1 && peeps[0].genderDesc().equals("man")
				&& (peeps[0].genderLookDesc().equals("women") || peeps[0].genderLookDesc().equals("women/trans women")));
	}

	public String nameDesc() {
		String ssm = singleStraightMan() ? " *SSM*" : "";
		String s = id() + ssm + " (aka " + pubname() + ") being ";
		s += " " + allNames() + "\n\t\t" + email;
		if ( remarks != null ) {
			s += "\n*Remarks: " + remarks;
		}
		if ( notes != null ) {
			s += "\n*Notes: " + notes;
		}
		if ( getReferred() != null ) {

			s += "\n*Referred: " + referred;
		}
		if ( friends != null ) {
			s += "\n*Friends: " + friends;
		}
		if ( needChildcare() ) {
			s += "\n*Childcare: " + getChildcareDetails();
		}
		return s;
	}
	
	
	public String entry( boolean fullDesc ) {
		String isComing = (isComing() ? "" : " (not coming)" ) + (hasPaid() ? "" : " (hasn't paid)");
		isComing += stationary ? " (stat)" : "";

		String s = id() + " (aka " + pubname() + ")" + isComing + " is " + geekCode();
		if ( fullDesc ) {
			s += "\n\t\t" + email;
			if ( remarks != null ) {
				s += "\n*Remarks: " + remarks;
			}
			if ( notes != null ) {
				s += "\n*Notes: " + notes;
			}
			if ( getReferred() != null ) {

				s += "\n*Referred: " + referred;
			}
			if ( friends != null ) {
				s += "\n*Friends: " + friends;
			}
			if ( needChildcare() ) {
				s += "\n*Childcare: " + getChildcareDetails();
			}
		}
		/*if ( )
	if ( )
		if ( write_comments_flag ) {
			outputString += "," + referred + "," + friends + "," + remarks;
		}

		outputString += "," + geekCode() + "," + WU.yesBlank(coming) + "," + getNotes();
		 */
		return s;
	}

	private boolean hasPaid() {
		return paid;
	}

	public void setChildcareDetails(String childcareDetails) {
		this.childcareDetails = cleanString(childcareDetails);
	}

	public String getChildcareDetails() {
		return childcareDetails;
	}

	public void setNeedChildcare(boolean needChildcare) {
		this.needChildcare = needChildcare;
	}

	public boolean needChildcare() {
		return needChildcare;
	}

	public void setReferred(String referred) {
		this.referred = cleanString(referred);
	}

	public String getReferred() {
		return referred;
	}


	public void setLocations(String string) {
		for (String location :  string.split(",") ) {
			if (location.equals( "EB")) {
				fromEB = true;
				continue;
			}
			if (location.equals( "SB")) {
				fromSB = true;
				continue;
			}
			if (location.equals( "NB")) {
				fromNB = true;
				continue;
			}
			if (location.equals( "SF")) {
				fromSF = true;
				continue;
			}
			if (location.equals( "PN")) {
				fromPN = true;
				continue;
			}
			if (location.equals( "SE")) {
				fromSE = true;
				continue;
			}
		}	
	}

	public void addPeep(Person p) {
		Person[] p2 = new Person[ numPeeps + 1 ];

		for ( int i = 0; i < numPeeps; i++ ) {
			p2[i] = peeps[i];
		}
		peeps = p2;
		peeps[numPeeps] = p;
		numPeeps++;
	}

	public void setPrimary(boolean b, int pos) {
		checkPeep(pos);
		peeps[pos].noPrimary = b;
	}

	public void setPubname(String pubname) {
		this.pubname = cleanString(pubname);
	}

	public String pubname() {
		return pubname;
	}

	public void setComments(String remarks) {
		if ( remarks == null || remarks.trim().equals("")) {
			return;
		}
		this.remarks = cleanString(remarks);
	}

	public void setPaid(boolean boolean1) {
		paid = boolean1;
	}

	public void setStationary(boolean boolean1) {
		stationary = boolean1;
	}

	public void setPending(boolean pending) {
		this.pending = pending;
	}

	public boolean pending() {
		return pending;
	}



}
